local skynet = require "skynet"
local Service = require "core.Service"
local Services = require "global.Services"
local MongoCollection = require "enum.MongoCollection"

local rawset = rawset

-- mongo 单例
---@type table<MongoCollection, MongoAgent> | MongoAgent
local M = Service:new()
skynet.init(function()
    local agent = Services.MONGO_POOL:bind(skynet.self())
    M:_setAddress(agent)
end)

setmetatable(M, {
    __index = function(ser, dbOrCmd)
        -- service 的属性
        if Service[dbOrCmd] then
            return Service[dbOrCmd]
        end

        -- db 集合
        local collection = setmetatable({}, {
            -- 获取到集合，直接进行处理
            __index = function(t, cmd)
                assert(MongoCollection[dbOrCmd], "mongo_collection not found")
                -- 获取到参数，还要继续获取更深层的数据，表示针对 db 的集合操作
                local function callback(arg1, ...)
                    if arg1 == t then
                        return skynet.call(ser.address, "lua", cmd, dbOrCmd, ...)
                    end

                    skynet.send(ser.address, "lua", cmd, dbOrCmd, arg1, ...)
                end

                rawset(t, cmd, callback)
                return callback
            end,
            -- 直接从 db 获取属性，当做函数调用，意味着直接调用 MongoAgent 的函数
            __call = function(t, arg1, ...)
                -- 此时传入的第一个参数可能是 M
                if arg1 == M then
                    return skynet.call(ser.address, "lua", dbOrCmd, ...)
                end

                return skynet.send(ser.address, "lua", dbOrCmd, arg1, ...)
            end
        })

        rawset(ser, dbOrCmd, collection)
        return collection
    end
})

return M
